
#include "ddcrypt.h"

int32_t
dd_base64_encode(uint8_t *in, uint32_t inl, uint8_t *out){
    int32_t outl = EVP_EncodeBlock(out, in, inl);
    if (outl < 0){
        return -1;
    }
    return outl;
}

int32_t
dd_base64_decode(uint8_t *in, uint32_t inl, uint8_t * out){
    int32_t outl = 0;
    int32_t ret = 0;
    if ('=' == in[inl - 1])
        ret++;
    if ('=' == in[inl - 2])
        ret++;
    outl = EVP_DecodeBlock(out, in, inl);
    if (0 > outl){
        printf("EVP_DecodeBlock failed\n");
        return -1;
    }
    out[outl - ret] = '\0';
    return outl - ret;
}

int32_t
dd_sign_with_rsa(uint8_t * in, uint32_t inl, uint8_t * out, EVP_MD *type, EVP_PKEY* key){
    EVP_MD_CTX md_ctx;
    EVP_SignInit(&md_ctx, type);
    EVP_SignUpdate(&md_ctx, in, inl);

    uint32_t sign_len = EVP_PKEY_size(key);
    uint8_t* sign_buf = (uint8_t *) OPENSSL_malloc(sign_len);
    uint8_t* out_buf = (uint8_t *) OPENSSL_malloc(sign_len * 2);

    int32_t ret = EVP_SignFinal(&md_ctx, sign_buf, &sign_len, key);
    if ( ret != 1)
        printf("EVP_SignFinal failed\n");
    else{
        uint32_t out_len = EVP_EncodeBlock(out_buf, sign_buf, sign_len);
        if (out_len < 0){
            ret = -1;
            printf("EVP_EncodeBlock failed\n");
        }else{
            memcpy(out, out_buf, out_len);
        }
    }

    OPENSSL_free(sign_buf);
    OPENSSL_free(out_buf);
    return 1 == ret ? 0 : -1;
}

EVP_PKEY *
dd_get_rsa_PKCS1_key(uint8_t * in, uint32_t inl, int32_t private){
    RSA* rsa = dd_get_rsa_key(in, inl, private);
    if(!rsa){
        printf("dd_get_rsa_key failed !\n");
        return NULL;
    }
    EVP_PKEY* key = EVP_PKEY_new();
    if(EVP_PKEY_assign_RSA(key, rsa) != 1){
        printf("EVP_PKEY_assign_RSA failed !\n");
        RSA_free(rsa);
        EVP_PKEY_free(key);
        return NULL;
    }
    return key;
}

RSA *
dd_get_rsa_key(uint8_t * in, uint32_t inl, int32_t private){
    uint8_t * key_buf = malloc(inl);
    int32_t key_len = dd_base64_decode(in, inl, key_buf);
    if (key_len < 0){
        printf("dd_base64_decode key failed !\n");
        return NULL;
    }

    //d2i_RSA_PUBKEY
    uint8_t *p = key_buf;
    RSA *rsa = (private == 0) ?
                    d2i_RSA_PUBKEY(NULL, &p, key_len) :
                    d2i_RSAPrivateKey(NULL, &p, key_len);
    return rsa;
}